#!usr/bin/env python  
# -*- coding:utf-8 _*-
""" 
@author:robot
@file: ct_api_publish_v1.py
@version:
@time: 2022/05/06 
"""
import time

import allure

from TapClientConnector import TapClientConnector
from TapClientCore.T06_Tapdata_feature.v2.TPF06_modules.tpf_api_requests import TPFAPIRequests
from TapClientCore.T06_Tapdata_feature.v2.TPF06_modules.tpf_modules import TPFModules
from TapClientCore.T06_Tapdata_feature.v2.TPF05_meta.tpf_meta import TPFMeta
from TapClientCore.T07_CaseTemplate.v2.CT01_datasource.ct_datasource import CTDataSource
from TapClientCore.T07_CaseTemplate.v2.CT03_task.ct_task import CTTaskUtil
from TapUtil.logfunc.logger import logger


class CTApiPublish(TPFMeta, TPFModules, CTTaskUtil, CTDataSource, TPFAPIRequests):
    # 创建api 准备
    def api_publish_prepare(self, source_info, source_table):
        # 数据源信息获取
        with allure.step('数据源信息获取'):
            connection_id = self.get_datasource_id_by_db_info(source_info)
            api_name = source_info.get('name')
            api_path = f'{api_name}_{source_table}'
            # 根据表名和数据源去获取table_id
            table_id = self.get_metadataInstances_id_by_source_id_and_table_name(connection_id, source_table).get('id')
            source_field = self.get_meta_fields_not_pop_id_by_id(table_id)
            # info print
            logger.info(f'api_name: {api_name}')
            logger.info(f'table_id: {table_id}')
            logger.info(f'source_field: {source_field}')
            logger.info(f'api_path: {api_path}')
            return connection_id, api_name, source_table, source_field, api_path

    # api  创建 发布
    def api_publish(self, args):
        with allure.step('创建发布，发布'):
            # 创建发布
            create_response = self.create_api_publish(*args)
            # 激活发布
            self.active_modules_api_server_by_name(args[1])
            # 等待api发布成功
            time.sleep(30)
            self.wait_api_server_running()

    # 源查询与api查询比对
    def tap_api_data_check(self, source_info, source_table, api_data):
        with allure.step('数据校验:数据库-apiserver'):
            source_connector = self.init_connector(source_info)
            if source_connector.database_type in ['mongodb']:
                tmp_1 = []
                source_result = self.tap_query(source_connector, table=source_table, column=None)
                for j in source_result:
                    tmp_2 = {}
                    for k in j:
                        from bson import Decimal128
                        from bson import ObjectId
                        if isinstance(j[k], Decimal128):
                            tmp_2[k] = int(j[k].to_decimal())
                        if isinstance(j[k], ObjectId):
                            tmp_2[k] = str(j[k])
                        else:
                            tmp_2[k] = j[k]
                    tmp_1.append(tmp_2)
                logger.info(tmp_1)
                logger.info(api_data)
                assert tmp_1 == api_data
            else:
                source_result = self.tap_query(source_connector, table=source_table)
                tmp_1 = []
                for j in api_data:
                    tmp_2 = []
                    for i in source_connector.tapclient_connector.TABLE_DESCRIPTION:
                        for k in j:
                            if i == k:
                                t = j[k]
                                from bson import Decimal128
                                if isinstance(j[k], Decimal128):
                                    t = int(j[k].to_decimal())
                                from bson import ObjectId
                                if isinstance(j[k], ObjectId):
                                    t = str(j[k])
                                tmp_2.append(t)
                    tmp_1.append(tuple(tmp_2))
                logger.info(source_result)
                logger.info(tmp_1)
                assert source_result == tmp_1

    # insert ,update, delete cdc 操作
    @staticmethod
    def api_cdc(func, *args):
        func(*args)
        time.sleep(5)

    # api query1
    def CT_API_PUBLISH_QUERY1(self, data, countlist):
        with allure.step('获取可用表'):
            data = self.lock_and_only_get_table(data)
        operate = data.pop('operate')
        operate_source = operate.get('source')
        source_info = operate_source.get('source_info')
        source_table = operate_source.get('table')
        source_where_column = operate_source.get('where')
        # connector
        with allure.step('源数据库初始化'):
            _source = self.init_connector(source_info)
        _source.tapclient_connector.CURRENT_TABLE = source_table
        source_delete = _source.tapclient_connector.generate_delete(
            source_where_column
        )
        with allure.step('执行前删除要插入的数据'):
            _source.tapclient_connector.exec(source_delete)
        # 数据源信息获取
        # 获取api publish 的info，-1 为api_path
        api_publish_prepare_info = self.api_publish_prepare(source_info, source_table)
        api_path = api_publish_prepare_info[-1]
        # 创建发布
        self.api_publish(api_publish_prepare_info[0:-1])
        # 查询
        api_query_res = self.api_query(api_path)
        assert self.api_count(api_path) == countlist
        self.tap_api_data_check(source_info, source_table, api_query_res)

    # api query2
    def CT_API_PUBLISH_QUERY2(self, data, countlist):
        with allure.step('获取可用表'):
            data = self.lock_and_only_get_table(data)

        operate = data.pop('operate')
        operate_source = operate.get('source')
        source_info = operate_source.get('source_info')
        source_table = operate_source.get('table')
        source_where_column = operate_source.get('where')
        # connector
        with allure.step('源数据库初始化'):
            _source = self.init_connector(source_info)
        _source.tapclient_connector.CURRENT_TABLE = source_table
        source_delete = _source.tapclient_connector.generate_delete(
            source_where_column
        )
        with allure.step('执行前删除要插入的数据'):
            _source.tapclient_connector.exec(source_delete)
        # 数据源信息获取
        # 获取api publish 的info，-1 为api_path
        api_publish_prepare_info = self.api_publish_prepare(source_info, source_table)
        api_path = api_publish_prepare_info[-1]
        # 创建发布
        self.api_publish(api_publish_prepare_info[0:-1])
        # 查询
        api_query_res = self.api_query3(api_path)
        assert self.api_count(api_path) == countlist
        self.tap_api_data_check(source_info, source_table, api_query_res)

    # connector cdc insert, update, delete
    def CT_API_PUBLISH_CDC_CONNECTOR(self, data, countlist):
        record_id = None
        source_delete = None
        task_name = None
        try:
            # 并行案例初始化
            with allure.step('获取可用表'):
                data = self.lock_and_get_table(data)
                record_id = data.get('id')
            # operate info
            operate = data.pop('operate')
            operate_source = operate.get('source')
            operate_target = operate.get('target')
            source_info = operate_source.get('source_info')

            # ddl and dml
            source_table = operate_source.get('table')
            source_insert_column = operate_source.get('insert')
            source_update_column = operate_source.get('update')
            source_where_column = operate_source.get('where')
            # connector
            with allure.step('源数据库初始化'):
                _source = self.init_connector(source_info)
            _source.tapclient_connector.CURRENT_TABLE = source_table
            source_insert = _source.tapclient_connector.generate_insert(
                source_insert_column
            )
            source_update = _source.tapclient_connector.generate_update(
                source_update_column,
                source_where_column
            )
            source_delete = _source.tapclient_connector.generate_delete(
                source_where_column
            )
            with allure.step('执行前删除要插入的数据'):
                _source.tapclient_connector.exec(source_delete)
            # 数据源信息获取
            # 获取api publish 的info，-1 为api_path
            api_publish_prepare_info = self.api_publish_prepare(source_info, source_table)
            api_path = api_publish_prepare_info[-1]
            # 创建发布
            self.api_publish(api_publish_prepare_info[0:-1])

            with allure.step('connector insert'):
                self.api_cdc(_source.tapclient_connector.exec, source_insert)
                with allure.step('insert check'):
                    api_query_res = self.api_query3(api_path)
                    self.tap_api_data_check(source_info, source_table, api_query_res)
                assert self.api_count(api_path) == countlist[0]

            with allure.step('connector update'):
                self.api_cdc(_source.tapclient_connector.exec, source_update)
                with allure.step('update check'):
                    api_query_res = self.api_query3(api_path)
                    self.tap_api_data_check(source_info, source_table, api_query_res)
                assert self.api_count(api_path) == countlist[1]

            with allure.step('connector delete'):
                self.api_cdc(_source.tapclient_connector.exec, source_delete)
                with allure.step('delete check'):
                    api_query_res = self.api_query3(api_path)
                    self.tap_api_data_check(source_info, source_table, api_query_res)
                    assert self.api_count(api_path) == countlist[2]
        except Exception as e:
            self.release_table(record_id)
            logger.info(e)
            _source.tapclient_connector.exec(source_delete)
            assert False
        finally:
            self.release_table(record_id)
            try:
                _source.tapclient_connector.close()
            except Exception as e:
                pass

    def CT_API_PUBLISH_CDC_API(self, data, countlist):
        record_id = None
        source_delete = None
        task_name = None
        try:
            # 并行案例初始化
            with allure.step('获取可用表'):
                data = self.lock_and_get_table(data)
                record_id = data.get('id')
            # operate info
            operate = data.pop('operate')
            operate_source = operate.get('source')
            source_info = operate_source.get('source_info')
            source_table = operate_source.get('table')
            source_where_column = operate_source.get('where')
            # connector
            with allure.step('源数据库初始化'):
                _source = self.init_connector(source_info)
            _source.tapclient_connector.CURRENT_TABLE = source_table
            source_delete = _source.tapclient_connector.generate_delete(
                source_where_column
            )
            with allure.step('执行前删除要插入的数据'):
                _source.tapclient_connector.exec(source_delete)
            # 数据源信息获取
            # 获取api publish 的info，-1 为api_path
            api_publish_prepare_info = self.api_publish_prepare(source_info, source_table)
            api_path = api_publish_prepare_info[-1]
            # 创建发布
            self.api_publish(api_publish_prepare_info[0:-1])
            pk = 2
            insert_data = {
                'pk': pk,
                'title': 'title'
            }
            update_data = {
                'pk': pk,
                'title': 'update'
            }
            if source_info.get('database_type') == 'mongodb':
                pk = '62a084ea7a0067390e839fb0'
                insert_data.update(
                    {'_id': '62a084ea7a0067390e839fb0'}
                )
            # insert
            with allure.step('api insert'):
                self.api_cdc(self.api_insert, api_path, insert_data)
                with allure.step('api insert check'):
                    api_query_res = self.api_query3(api_path)
                    self.tap_api_data_check(source_info, source_table, api_query_res)
                    assert self.api_count(api_path) == countlist[1]
            # update
            with allure.step('api update'):
                self.api_cdc(self.api_update, api_path, pk, update_data)
                with allure.step('api update check'):
                    api_query_res = self.api_query3(api_path)
                    self.tap_api_data_check(source_info, source_table, api_query_res)
                    assert self.api_count(api_path) == countlist[1]
            # delete
            with allure.step('api delete'):
                self.api_cdc(self.api_delete, api_path, pk)
                with allure.step('api delete check'):
                    api_query_res = self.api_query3(api_path)
                    self.tap_api_data_check(source_info, source_table, api_query_res)
                    assert self.api_count(api_path) == countlist[2]
        except Exception as e:
            self.release_table(record_id)
            logger.info(e)
            _source.tapclient_connector.exec(source_delete)
            assert False
        finally:
            self.release_table(record_id)
            try:
                _source.tapclient_connector.close()
            except Exception as e:
                pass
